/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { View, useWindowDimensions, TouchableWithoutFeedback } from 'react-native';
import Animated, { useSharedValue, withTiming, withSpring, runOnJS, useWorkletCallback, cancelAnimation } from 'react-native-reanimated';
import type { WithSpringConfig } from 'react-native-reanimated';
import type { AdaptiveCenterSheetProps } from './types';
import type { AdaptiveSheetMethods } from '../../types';
import AdaptiveCenterSheetHeader from './AdaptiveCenterSheetHeader';
import { styles } from './styles';
import {
  DEFAULT_INDEX,
  DEFAULT_ANIMATE_ON_MOUNT,
  DEFAULT_WIDTH,
  DEFAULT_HEIGHT,
  DEFAULT_MAX_WIDTH,
  DEFAULT_SHOW_HEADER,
  DEFAULT_SHOW_CLOSE_BUTTON,
  DEFAULT_BACKDROP_OPACITY,
  DEFAULT_BACKDROP_COLOR,
  DEFAULT_ENABLE_BACKDROP_DISMISS,
  DEFAULT_CLOSE_BUTTON_COLOR,
  DEFAULT_TOP_INSET,
  DEFAULT_BOTTOM_INSET,
  ANIMATION_OPACITY_FROM,
  ANIMATION_OPACITY_TO,
  DEFAULT_FADE_ANIMATION_CONFIG,
  DEFAULT_BUTTON_POSITION,
  DEFAULT_HEADER_HEIGHT,
  DEFAULT_VERTICAL_MARGIN,
} from './constants';

type AdaptiveCenterSheet = AdaptiveSheetMethods;

const AdaptiveCenterSheetComponent = forwardRef<AdaptiveCenterSheet, AdaptiveCenterSheetProps>(function AdaptiveCenterSheet(
  {
    // configuration
    index = DEFAULT_INDEX,
    animateOnMount = DEFAULT_ANIMATE_ON_MOUNT,

    // dimensions
    width = DEFAULT_WIDTH,
    height = DEFAULT_HEIGHT,
    maxWidth = DEFAULT_MAX_WIDTH,
    verticalMargin = DEFAULT_VERTICAL_MARGIN,

    // layout
    topInset = DEFAULT_TOP_INSET,
    bottomInset = DEFAULT_BOTTOM_INSET,

    // styles
    containerStyle,
    contentStyle,
    backdropStyle,

    // header
    title,
    headerHeight,
    showHeader = DEFAULT_SHOW_HEADER,
    headerComponent: HeaderComponent,
    headerStyle,
    titleStyle,
    showCloseButton = DEFAULT_SHOW_CLOSE_BUTTON,
    closeButtonPosition = DEFAULT_BUTTON_POSITION,
    closeButtonStyle,
    closeButtonColor = DEFAULT_CLOSE_BUTTON_COLOR,
    closeButtonComponent,
    leftButton,
    rightButton,
    onLeftPress,
    onRightPress,

    // backdrop
    backdropOpacity = DEFAULT_BACKDROP_OPACITY,
    backdropColor = DEFAULT_BACKDROP_COLOR,
    enableBackdropDismiss = DEFAULT_ENABLE_BACKDROP_DISMISS,

    // animation
    animationConfigs,

    // callbacks
    onStateChange,
    onSizeChange,

    // children
    children,
  },
  ref,
) {
    // 使用 useWindowDimensions Hook 自动响应屏幕尺寸变化
  const { width: windowWidth, height: windowHeight } = useWindowDimensions();
  const [currentIndex, setCurrentIndex] = useState(index);

  const isMountedRef = useRef(false);

  const isFirstMount = !isMountedRef.current;
  const shouldAnimateOnMount = isFirstMount && animateOnMount && index !== -1;
  const initialOpacity = shouldAnimateOnMount ? ANIMATION_OPACITY_FROM : index === -1 ? ANIMATION_OPACITY_FROM : ANIMATION_OPACITY_TO;
  const initialBackdropOpacity = shouldAnimateOnMount ? 0 : index === -1 ? 0 : backdropOpacity;

  const animatedOpacity = useSharedValue(initialOpacity);
  const animatedBackdropOpacity = useSharedValue(initialBackdropOpacity);

  useEffect(() => {
    isMountedRef.current = true;
  }, []);

  // 计算弹窗尺寸
  const sheetWidth = useMemo(() => {
    if (typeof width === 'string' && width.includes('%')) {
      const percentage = parseFloat(width.replace('%', '')) / 100;
      const calculatedWidth = windowWidth * percentage;
      return Math.min(calculatedWidth, maxWidth);
    }
    return Math.min(Number(width), maxWidth);
  }, [width, maxWidth, windowWidth]);

  const sheetHeight = useMemo(() => {
    if (height === 'auto') {
      return undefined; // 自动高度
    }
    if (typeof height === 'string' && height.includes('%')) {
      const percentage = parseFloat(height.replace('%', '')) / 100;
      return windowHeight * percentage;
    }
    return Number(height);
  }, [height, windowHeight]);

  const sheetMaxHeight = useMemo(() => {
    return windowHeight - verticalMargin * 2;
  }, [verticalMargin, windowHeight]);

  const handleIndexChange = useCallback(
    (newIndex: number) => {
      setCurrentIndex(newIndex);
      onStateChange?.(newIndex);

      // Trigger onSizeChange when sheet opens (from -1 to 0)
      if (newIndex === 0 && onSizeChange) {
        // Call onSizeChange with the actual dimensions
        onSizeChange({
          width: sheetWidth,
          height: sheetHeight || 0,
        });
      }
    },
    [onStateChange, onSizeChange, sheetWidth, sheetHeight],
  );

  // 打开动画
  const animateToOpen = useWorkletCallback(() => {
    'worklet';

    cancelAnimation(animatedOpacity);
    cancelAnimation(animatedBackdropOpacity);

    if (animationConfigs) {
      animatedOpacity.value = withSpring(ANIMATION_OPACITY_TO, animationConfigs as unknown as WithSpringConfig);
      animatedBackdropOpacity.value = withSpring(backdropOpacity, animationConfigs as unknown as WithSpringConfig);
    } else {
      animatedOpacity.value = withTiming(ANIMATION_OPACITY_TO, DEFAULT_FADE_ANIMATION_CONFIG);
      animatedBackdropOpacity.value = withTiming(backdropOpacity, DEFAULT_FADE_ANIMATION_CONFIG);
    }

    runOnJS(handleIndexChange)(0);
  }, [animationConfigs, backdropOpacity, handleIndexChange, animatedOpacity, animatedBackdropOpacity]);

  const animateToClose = useWorkletCallback(() => {
    'worklet';

    cancelAnimation(animatedOpacity);
    cancelAnimation(animatedBackdropOpacity);

    if (animationConfigs) {
      animatedOpacity.value = withSpring(ANIMATION_OPACITY_FROM, animationConfigs as unknown as WithSpringConfig);
      animatedBackdropOpacity.value = withSpring(0, animationConfigs as unknown as WithSpringConfig);
    } else {
      animatedOpacity.value = withTiming(ANIMATION_OPACITY_FROM, DEFAULT_FADE_ANIMATION_CONFIG);
      animatedBackdropOpacity.value = withTiming(0, DEFAULT_FADE_ANIMATION_CONFIG);
    }

    runOnJS(handleIndexChange)(-1);
  }, [animationConfigs, handleIndexChange, animatedOpacity, animatedBackdropOpacity]);

  const snapToIndex = useCallback(
    (nextIndex: number) => {
      if (nextIndex === currentIndex) {
        return;
      }

      if (nextIndex === -1) {
        animateToClose();
      } else if (nextIndex === 0) {
        animateToOpen();
      }
    },
    [animateToOpen, animateToClose, currentIndex],
  );

  const snapToPosition = useCallback((_position: number | string) => {
    if (__DEV__) {
      console.warn('[AdaptiveCenterSheet] snapToPosition is not supported for center sheets');
    }
  }, []);

  const expand = useCallback(() => {
    snapToIndex(0);
  }, [snapToIndex]);

  const collapse = useCallback(() => {
    snapToIndex(-1);
  }, [snapToIndex]);

  const close = useCallback(() => {
    snapToIndex(-1);
  }, [snapToIndex]);

  const forceClose = useCallback(() => {
    snapToIndex(-1);
  }, [snapToIndex]);

  useImperativeHandle(ref, () => ({
    snapToIndex,
    snapToPosition,
    expand,
    collapse,
    close,
    forceClose,
  }));

  const backdropStaticStyle = useMemo(() => [styles.backdrop, { backgroundColor: backdropColor }, backdropStyle], [backdropColor, backdropStyle]);

  const containerStyleWithInsets = useMemo(() => [styles.container, {}, containerStyle], [containerStyle]);

  const contentMaxHeight = useMemo(() => {
  if (!sheetHeight) {
    return undefined;
  }

  let maxHeight = sheetHeight;

  if (showHeader) {
    const actualHeaderHeight = headerHeight || DEFAULT_HEADER_HEIGHT;
    maxHeight -= actualHeaderHeight;
  }

  return Math.max(0, maxHeight);
}, [sheetHeight, showHeader, headerHeight]);

  const sheetStaticStyle = useMemo(
    () => [
      styles.sheet,
      {
        width: sheetWidth,
        height: sheetHeight,
        maxHeight: sheetMaxHeight, 
      },
      contentStyle,
    ],
    [sheetWidth, sheetHeight, sheetMaxHeight, contentStyle],
  );

  // 挂载动画
  useEffect(() => {
    if (animateOnMount && index !== -1) {
      requestAnimationFrame(() => {
        snapToIndex(index);
      });
    }
  }, [animateOnMount, index, snapToIndex]);

  if (currentIndex === -1) {
    return null;
  }

  return (
    <>
      {/* Backdrop */}
      <TouchableWithoutFeedback onPress={enableBackdropDismiss ? close : undefined} disabled={!enableBackdropDismiss}>
        <Animated.View
          style={[
            backdropStaticStyle,
            {
              opacity: animatedBackdropOpacity, 
            },
          ]}
          pointerEvents="auto"
        />
      </TouchableWithoutFeedback>

      {/* Sheet Container */}
      <View style={containerStyleWithInsets} pointerEvents="box-none">
        <Animated.View
          style={[
            sheetStaticStyle,
            {
              opacity: animatedOpacity,
            },
          ]}
          pointerEvents="auto">
          {/* Header */}
          {showHeader &&
            (HeaderComponent ? (
              <HeaderComponent
                title={title}
                height={headerHeight}
                leftButton={leftButton}
                rightButton={rightButton}
                onLeftPress={onLeftPress}
                onRightPress={onRightPress}
                titleStyle={titleStyle}
                containerStyle={headerStyle}
                closeButtonColor={closeButtonColor}
                sheetType="center"
              />
            ) : (
              <AdaptiveCenterSheetHeader
                title={title}
                height={headerHeight}
                showCloseButton={showCloseButton}
                closeButtonPosition={closeButtonPosition}
                onClose={close}
                headerStyle={headerStyle}
                titleStyle={titleStyle}
                closeButtonStyle={closeButtonStyle}
                closeButtonColor={closeButtonColor}
                closeButtonComponent={closeButtonComponent}
                leftButton={leftButton}
                rightButton={rightButton}
                onLeftPress={onLeftPress}
                onRightPress={onRightPress}
              />
            ))}

          {/* Content */}
          <View style={[styles.contentContainer, { maxHeight: contentMaxHeight }]}>{children}</View>
        </Animated.View>
      </View>
    </>
  );
});

const AdaptiveCenterSheet = memo(AdaptiveCenterSheetComponent);
AdaptiveCenterSheet.displayName = 'AdaptiveCenterSheet';

export default AdaptiveCenterSheet;
